home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dskut / aspisrc.zip / DIFFARCH.C < prev    next >
C/C++ Source or Header  |  1992-01-26  |  16KB  |  695 lines

  1. /* Diff files from a tar archive.
  2.    Copyright (C) 1988 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * Diff files from a tar archive.
  22.  *
  23.  * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
  24.  *
  25.  * @(#) diffarch.c 1.10 87/11/11 - gnu
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32.  
  33. #ifdef BSD42
  34. #include <sys/file.h>
  35. #endif
  36.  
  37. #ifndef MSDOS
  38. #include <sys/ioctl.h>
  39. #if !defined(USG) || defined(HAVE_MTIO)
  40. #include <sys/mtio.h>
  41. #endif
  42. #else
  43. #include <fcntl.h>
  44. #endif
  45.  
  46. #ifdef USG
  47. #include <fcntl.h>
  48. #endif
  49.  
  50. /* Some systems don't have these #define's -- we fake it here. */
  51. #ifndef O_RDONLY
  52. #define    O_RDONLY    0
  53. #endif
  54. #ifndef    O_NDELAY
  55. #define    O_NDELAY    0
  56. #endif
  57.  
  58. #ifndef S_IFLNK
  59. #define lstat stat
  60. #endif
  61.  
  62. extern int errno;            /* From libc.a */
  63. extern char *valloc();            /* From libc.a */
  64.  
  65. #include "tar.h"
  66. #include "port.h"
  67. #include "rmt.h"
  68.  
  69. extern union record *head;        /* Points to current tape header */
  70. extern struct stat hstat;        /* Stat struct corresponding */
  71. extern int head_standard;        /* Tape header is in ANSI format */
  72.  
  73. extern void print_header();
  74. extern void skip_file();
  75. extern void skip_extended_headers();
  76.  
  77. extern FILE *msg_file;
  78.  
  79. int now_verifying = 0;        /* Are we verifying at the moment? */
  80.  
  81. int    diff_fd;        /* Descriptor of file we're diffing */
  82.  
  83. char    *diff_buf = 0;        /* Pointer to area for reading
  84.                        file contents into */
  85.  
  86. char    *diff_dir;        /* Directory contents for LF_DUMPDIR */
  87.  
  88. int different = 0;
  89.  
  90. /*struct sp_array *sparsearray;
  91. int         sp_ar_size = 10;*/
  92. /*
  93.  * Initialize for a diff operation
  94.  */
  95. diff_init()
  96. {
  97.  
  98.     /*NOSTRICT*/
  99.     diff_buf = (char *) valloc((unsigned)blocksize);
  100.     if (!diff_buf) {
  101.         msg("could not allocate memory for diff buffer of %d bytes",
  102.             blocksize);
  103.         exit(EX_ARGSBAD);
  104.     }
  105. }
  106.  
  107. /*
  108.  * Diff a file against the archive.
  109.  */
  110. void
  111. diff_archive()
  112. {
  113.     register char *data;
  114.     int check, namelen;
  115.     int err;
  116.     long offset;
  117.     struct stat filestat;
  118.     int compare_chunk();
  119.     int compare_dir();
  120. #ifndef __MSDOS__
  121.     dev_t    dev;
  122.     ino_t    ino;
  123. #endif
  124.     char *get_dir_contents();
  125.     long from_oct();
  126.     long lseek();
  127.  
  128.     errno = EPIPE;            /* FIXME, remove perrors */
  129.  
  130.     saverec(&head);            /* Make sure it sticks around */
  131.     userec(head);            /* And go past it in the archive */
  132.     decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  133.  
  134.     /* Print the record from 'head' and 'hstat' */
  135.     if (f_verbose) {
  136.         if(now_verifying)
  137.             fprintf(msg_file,"Verify ");
  138.         print_header();
  139.     }
  140.  
  141.     switch (head->header.linkflag) {
  142.  
  143.     default:
  144.         msg("Unknown file type '%c' for %s, diffed as normal file",
  145.             head->header.linkflag, head->header.name);
  146.         /* FALL THRU */
  147.  
  148.     case LF_OLDNORMAL:
  149.     case LF_NORMAL:
  150.     case LF_SPARSE:
  151.     case LF_CONTIG:
  152.         /*
  153.          * Appears to be a file.
  154.          * See if it's really a directory.
  155.          */
  156.         namelen = strlen(head->header.name)-1;
  157.         if (head->header.name[namelen] == '/')
  158.             goto really_dir;
  159.  
  160.         
  161.         if(do_stat(&filestat)) {
  162.             if (head->header.isextended)
  163.                 skip_extended_headers();
  164.             skip_file((long)hstat.st_size);
  165.             different++;
  166.             goto quit;
  167.         }
  168.  
  169.         if ((filestat.st_mode & S_IFMT) != S_IFREG) {
  170.             fprintf(msg_file, "%s: not a regular file\n",
  171.                 head->header.name);
  172.             skip_file((long)hstat.st_size);
  173.             different++;
  174.             goto quit;
  175.         }
  176.  
  177.         filestat.st_mode &= ~S_IFMT;
  178.         if (filestat.st_mode != hstat.st_mode)
  179.             sigh("mode");
  180.         if (filestat.st_uid  != hstat.st_uid)
  181.             sigh("uid");
  182.         if (filestat.st_gid  != hstat.st_gid)
  183.             sigh("gid");
  184.         if (filestat.st_mtime != hstat.st_mtime)
  185.             sigh("mod time");
  186.         if (head->header.linkflag != LF_SPARSE &&
  187.                 filestat.st_size != hstat.st_size) {
  188.             sigh("size");
  189.             skip_file((long)hstat.st_size);
  190.             goto quit;
  191.         }
  192.  
  193.         diff_fd = open(head->header.name, O_NDELAY|O_RDONLY);
  194. #ifdef __MSDOS__
  195.                 setmode(diff_fd, O_BINARY);
  196. #endif
  197.         if (diff_fd < 0 && !f_absolute_paths) {
  198.             char tmpbuf[NAMSIZ+2];
  199.  
  200.             tmpbuf[0]='/';
  201.             strcpy(&tmpbuf[1],head->header.name);
  202.             diff_fd=open(tmpbuf, O_NDELAY|O_RDONLY);
  203.         }
  204.         if (diff_fd < 0) {
  205.             msg_perror("cannot open %s",head->header.name);
  206.             if (head->header.isextended)
  207.                 skip_extended_headers();
  208.             skip_file((long)hstat.st_size);
  209.             different++;
  210.             goto quit;
  211.         }
  212.         /*
  213.          * Need to treat sparse files completely differently here.
  214.          */
  215.         if (head->header.linkflag == LF_SPARSE)
  216.             diff_sparse_files(hstat.st_size);
  217.         else 
  218.             wantbytes((long)(hstat.st_size),compare_chunk);
  219.  
  220.         check = close(diff_fd);
  221.         if (check < 0)
  222.             msg_perror("Error while closing %s",head->header.name);
  223.  
  224.     quit:
  225.         break;
  226.  
  227. #ifndef __MSDOS__
  228.     case LF_LINK:
  229.         if(do_stat(&filestat))
  230.             break;
  231.         dev = filestat.st_dev;
  232.         ino = filestat.st_ino;
  233.         err = stat(head->header.linkname, &filestat);
  234.         if (err < 0) {
  235.             if (errno==ENOENT) {
  236.                 fprintf(msg_file, "%s: does not exist\n",head->header.name);
  237.             } else {
  238.                 msg_perror("cannot stat file %s",head->header.name);
  239.             }
  240.             different++;
  241.             break;
  242.         }
  243.         if(filestat.st_dev!=dev || filestat.st_ino!=ino) {
  244.             fprintf(msg_file, "%s not linked to %s\n",head->header.name,head->header.linkname);
  245.             break;
  246.         }
  247.         break;
  248. #endif
  249.  
  250. #ifdef S_IFLNK
  251.     case LF_SYMLINK:
  252.     {
  253.         char linkbuf[NAMSIZ+3];
  254.         check = readlink(head->header.name, linkbuf,
  255.                  (sizeof linkbuf)-1);
  256.         
  257.         if (check < 0) {
  258.             if (errno == ENOENT) {
  259.                 fprintf(msg_file,
  260.                     "%s: no such file or directory\n",
  261.                     head->header.name);
  262.             } else {
  263.                 msg_perror("cannot read link %s",head->header.name);
  264.             }
  265.             different++;
  266.             break;
  267.         }
  268.  
  269.         linkbuf[check] = '\0';    /* Null-terminate it */
  270.         if (strncmp(head->header.linkname, linkbuf, check) != 0) {
  271.             fprintf(msg_file, "%s: symlink differs\n",
  272.                 head->header.linkname);
  273.             different++;
  274.         }
  275.     }
  276.         break;
  277. #endif
  278.  
  279.     case LF_CHR:
  280.         hstat.st_mode |= S_IFCHR;
  281.         goto check_node;
  282.  
  283. #ifdef S_IFBLK
  284.     /* If local system doesn't support block devices, use default case */
  285.     case LF_BLK:
  286.         hstat.st_mode |= S_IFBLK;
  287.         goto check_node;
  288. #endif
  289.  
  290. #ifdef S_IFIFO
  291.     /* If local system doesn't support FIFOs, use default case */
  292.     case LF_FIFO:
  293.         hstat.st_mode |= S_IFIFO;
  294.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  295.         goto check_node;
  296. #endif
  297.  
  298.     check_node:
  299.         /* FIXME, deal with umask */
  300.         if(do_stat(&filestat))
  301.             break;
  302.         if(hstat.st_rdev != filestat.st_rdev) {
  303.             fprintf(msg_file, "%s: device numbers changed\n", head->header.name);
  304.             different++;
  305.             break;
  306.         }
  307.         if(hstat.st_mode != filestat.st_mode) {
  308.             fprintf(msg_file, "%s: mode or device-type changed\n", head->header.name);
  309.             different++;
  310.             break;
  311.         }
  312.         break;
  313.  
  314.     case LF_DUMPDIR:
  315.         data=diff_dir=get_dir_contents(head->header.name,0);
  316.         wantbytes((long)(hstat.st_size),compare_dir);
  317.         free(data);
  318.         /* FALL THROUGH */
  319.  
  320.     case LF_DIR:
  321.         /* Check for trailing / */
  322.         namelen = strlen(head->header.name)-1;
  323.     really_dir:
  324.         while (namelen && head->header.name[namelen] == '/')
  325.             head->header.name[namelen--] = '\0';    /* Zap / */
  326.  
  327.         if(do_stat(&filestat))
  328.             break;
  329.         if((filestat.st_mode&S_IFMT)!=S_IFDIR) {
  330.             fprintf(msg_file, "%s is no longer a directory\n",head->header.name);
  331.             different++;
  332.             break;
  333.         }
  334.         if((filestat.st_mode&~S_IFMT) != hstat.st_mode)
  335.             sigh("mode");
  336.         break;
  337.  
  338.     case LF_VOLHDR:
  339.         break;
  340.  
  341.     case LF_MULTIVOL:
  342.         namelen = strlen(head->header.name)-1;
  343.         if (head->header.name[namelen] == '/')
  344.             goto really_dir;
  345.  
  346.         if(do_